package com.javaspeak.concurrency.pattern.application;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Logger;

import com.javaspeak.concurrency.pattern.actor.ActorRegistry;
import com.javaspeak.concurrency.pattern.actor.ActorRegistryImpl;

/**
 * @author John Dickerson
 */
public class StartApplication {

    public Logger logger = Logger.getLogger( StartApplication.class );


    private Collection<Trade> getTrades( long numberTrades ){

        Collection<Trade> trades = new ArrayList<Trade>( ( int )numberTrades );

        for ( int i=0; i<numberTrades; i++ ){

            Trade trade =
                new Trade( new Long( i ), new BigDecimal( i * 1000 ),
                        new BigDecimal( i * 100 ), Calendar.getInstance() );

            trades.add( trade );
        }

        return trades;
    }


    public void start() throws Exception {

        long numberTrades = 10000;

        ActorRegistry actorRegistry = ActorRegistryImpl.getInstance();
        actorRegistry.registerActor( new StartActorImpl() );
        actorRegistry.registerActor( new LogTradeActorImpl() );
        actorRegistry.registerActor( new ProcessTradeActorImpl() );

        logger.debug( "Getting " + numberTrades + " trades to send" );

        Collection<Trade> trades = getTrades( numberTrades );

        logger.debug( "Finished Getting " + numberTrades + " trades to send" );

        StartActor startActor =
            ( StartActor )actorRegistry.getActor(
                    StartActor.class );

        long timeBegin = ( new Date() ).getTime();

        for ( Trade trade : trades ){

            startActor.sendTrade( trade );
        }

        List<Trade> invalidTrades = new ArrayList<Trade>();

        for ( int i=0; i<numberTrades; i++ ){

            TradeConfirmation tradeConfirmation =
                    startActor.getTradeConfirmation();

            logger.debug( "Received trade confirmation with id: " +
                tradeConfirmation.getTrade().getTradeId() );

            if ( ! tradeConfirmation.isValid() ){

                invalidTrades.add( tradeConfirmation.getTrade() );
            }
        }

        long timeEnd = ( new Date() ).getTime();

        long elapsedTime = timeEnd - timeBegin;

        for ( Trade trade : invalidTrades ){

            logger.debug( "Trade with id: " + trade.getTradeId() +
                    " was invalid" );
        }

        logger.debug( "There were " + invalidTrades.size() +
                " invalid trades out of " + numberTrades + " trades" );

        logger.debug( "It took " + elapsedTime +
                " milliseconds to process " + numberTrades +
                    " trades with a chain of 4 actors" );

        actorRegistry.shutDown();
    }


    public static void main( String args[] ) throws Exception {

        BasicConfigurator.resetConfiguration();
        BasicConfigurator.configure();

        StartApplication startApplication = new StartApplication();
        startApplication.start();
    }
}
